package com.cloudkinto.generateUtils;

import cn.smallbun.screw.core.Configuration;
import cn.smallbun.screw.core.engine.EngineConfig;
import cn.smallbun.screw.core.engine.EngineFileType;
import cn.smallbun.screw.core.engine.EngineTemplateType;
import cn.smallbun.screw.core.execute.DocumentationExecute;
import cn.smallbun.screw.core.process.ProcessConfig;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;

/**
 * @author zhangyy
 * @date 2020/4/18 0:14
 * @description:
 */
@Slf4j
public class CodeGenerator {

    private static final String TABLE_NAME = "t_order_shopify_ship";

    //定义生成的包名
    private static final String PACKAGE = "order";

    //定义作者
    private static final String AUTHOR_NAME = "ding";


    //顶层包名
    private static final String PACKAGE_NAME = "com.cloudkinto";
    //定义表前缀
    private static final String TB_PREFIX = "t_";
    //数据库的链接
    private static final String DB_URL = "jdbc:mysql://192.168.1.63:3306/logistics?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=UTC";
    //数据库用户名
    private static final String USERNAME = "root";
    //数据库密码
    private static final String PASSWORD = "zz000000";
    //数据库驱动名
    private static final String DRIVER_NAME = "com.mysql.cj.jdbc.Driver";
    //数据库类型
    private static DbType dbType = DbType.MYSQL;

    /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        codeGeneration();
//        documentGeneration();
    }

    /**
     * 代码生成
     */
    public static void codeGeneration() {
        String projectPath = System.getProperty("user.dir");
        log.info("项目根路径:" + projectPath);

        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        //设置文件默认生成的目录  不用设置后面我们自定义指定生成的位置
        /*gc.setOutputDir(projectPath + "/src/main/java");*/
        //是否覆盖已有文件
        gc.setFileOverride(true);
        //生成后是否打开文件 默认true
        gc.setOpen(false);
        // 开启 activeRecord 模式
        gc.setActiveRecord(true);
        // XML 二级缓存
        gc.setEnableCache(false);
        // XML ResultMap 映射图
        gc.setBaseResultMap(true);
        // XML columList
        gc.setBaseColumnList(true);
        //设置主键类型
        gc.setIdType(IdType.AUTO);
        gc.setAuthor(AUTHOR_NAME);
        // 自定义文件命名，注意 %s 会自动填充表实体属性！
        gc.setEntityName("%sDo");
        gc.setMapperName("%sDao");
        gc.setServiceName("%sService");
        gc.setServiceImplName("%sServiceImpl");
        gc.setControllerName("%sController");
        gc.setXmlName("%sMapper");
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(dbType);
        //注意Mysql 驱动版本问题 我这为8版本
        dsc.setDriverName(DRIVER_NAME);
        dsc.setUsername(USERNAME);
        dsc.setPassword(PASSWORD);
        dsc.setUrl(DB_URL);
        dsc.setTypeConvert(new MySqlTypeConvert() {
            //自定义转换类型，将数据字段类型转化成特定的java类型
            @Override
            public DbColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
                System.out.println("转换类型：" + fieldType);
                //tinyint转换成Boolean
                if (fieldType.toLowerCase().contains("tinyint")) {
                    return DbColumnType.BOOLEAN;
                }
                //数据库中datetime生成对应实体 java.util.Date
                if (fieldType.toLowerCase().contains("datetime")) {
                    return DbColumnType.DATE;
                }
                return (DbColumnType) super.processTypeConvert(globalConfig, fieldType);
            }
        });
        mpg.setDataSource(dsc);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        /** 此处可以修改为您的表前缀，如果没有，注释掉即可*/
        strategy.setTablePrefix(new String[]{TB_PREFIX});
        /** 表名生成策略*/
        strategy.setNaming(NamingStrategy.underline_to_camel);
        /** 列名名生成策略*/
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        /** 需要生成的表*/
        strategy.setInclude(new String[]{TABLE_NAME});
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        strategy.setEntityTableFieldAnnotationEnable(true);
        strategy.setLogicDeleteFieldName("delete_flag");
        strategy.setEntitySerialVersionUID(true);
        strategy.setSuperControllerClass("com.cloudkinto.base.BaseController");
//        strategy.setVersionFieldName("version");
        mpg.setStrategy(strategy);

        // 指定包配置路径和生成包目录的位置  下面我们也可以自定义指定位置
        PackageConfig pc = new PackageConfig();
        pc.setParent(PACKAGE_NAME);
        pc.setController("controller" + StringPool.DOT + PACKAGE);
        pc.setService("service" + StringPool.DOT + PACKAGE);
        pc.setServiceImpl("service." + PACKAGE + ".impl");
        pc.setEntity("entity");
        pc.setMapper("dao");
        pc.setXml("mapper");
        mpg.setPackageInfo(pc);


        // 注入自定义配置，可以在 VM 中使用 cfg.abc 【可无】
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
            }
        };

        List<FileOutConfig> focList = new ArrayList<FileOutConfig>();

        // 调整 xml 生成目录演示
        focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
                return projectPath + "/logistics-dal/src/main/resources/mapper/" + tableInfo.getXmlName() + StringPool.DOT_XML;
            }
        });

        // 调整 dao 生成目录
        focList.add(new FileOutConfig("/templates/mapper.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/logistics-dal/src/main/java/com/cloudkinto/dao/" + tableInfo.getMapperName() + StringPool.DOT_JAVA;
            }
        });

        //调整 entity 生成目录
        focList.add(new FileOutConfig("/templates/entity.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/logistics-dal/src/main/java/com/cloudkinto/entity/" + tableInfo.getEntityName() + StringPool.DOT_JAVA;
            }
        });

        //调整 service 生成目录
        focList.add(new FileOutConfig("/templates/service.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/logistics-service/src/main/java/com/cloudkinto/service/" + PACKAGE + "/" + tableInfo.getServiceName() + StringPool.DOT_JAVA;
            }
        });

        //调整 serviceImpl 生成目录
        focList.add(new FileOutConfig("/templates/serviceImpl.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/logistics-service/src/main/java/com/cloudkinto/service/" + PACKAGE + "/impl/" + tableInfo.getServiceImplName() + StringPool.DOT_JAVA;
            }
        });

        //调整 controller 生成目录
        focList.add(new FileOutConfig("/templates/controller.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/logistics-web/src/main/java/com/cloudkinto/controller/" + PACKAGE + "/" + tableInfo.getControllerName() + StringPool.DOT_JAVA;
            }
        });

        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);


        // 自定义模板配置，可以 copy 源码 mybatis-plus/src/main/resources/templates 下面内容修改，
        // 放置自己项目的 src/main/resources/templates 目录下, 默认名称一下可以不配置，也可以自定义模板名称
        TemplateConfig tc = new TemplateConfig();
        // 如上任何一个模块如果设置 Null 将不生成该模块。
        /*tc.setController("/templates/controller.java.vm");
        tc.setEntity("templates/entity.java.vm");
        tc.setMapper("templates/mapper.java.vm");
        tc.setService("/templates/service.java.vm");
        tc.setServiceImpl("templates/serviceImpl.java.vm");
        tc.setXml(null);*/
        tc.setController(null);
        tc.setEntity(null);
        tc.setMapper(null);
        tc.setService(null);
        tc.setServiceImpl(null);
        tc.setXml(null);
        mpg.setTemplate(tc);
        // 执行生成
        mpg.execute();
    }

    /**
     * 文档生成
     */
    public static void documentGeneration() {
        String projectPath = System.getProperty("user.dir");
        //数据源
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName(DRIVER_NAME);
        hikariConfig.setJdbcUrl(DB_URL);
        hikariConfig.setUsername(USERNAME);
        hikariConfig.setPassword(PASSWORD);
        //设置可以获取tables remarks信息
        hikariConfig.addDataSourceProperty("useInformationSchema", "true");
        hikariConfig.setMinimumIdle(2);
        hikariConfig.setMaximumPoolSize(5);
        DataSource dataSource = new HikariDataSource(hikariConfig);
        //生成配置
        EngineConfig engineConfig = EngineConfig.builder()
                //生成文件路径
                .fileOutputDir(projectPath)
                //打开目录
                .openOutputDir(true)
                //文件类型
                .fileType(EngineFileType.HTML)
                //生成模板实现
                .produceType(EngineTemplateType.freemarker)
                //自定义文件名称
                .fileName("sql_document").build();

        //忽略表
        ArrayList<String> ignoreTableName = new ArrayList<>();
        ignoreTableName.add("test_user");
        ignoreTableName.add("test_group");
        //忽略表前缀
        ArrayList<String> ignorePrefix = new ArrayList<>();
        ignorePrefix.add("test_");
        //忽略表后缀
        ArrayList<String> ignoreSuffix = new ArrayList<>();
        ignoreSuffix.add("_test");
        ProcessConfig processConfig = ProcessConfig.builder()
                //指定生成逻辑、当存在指定表、指定表前缀、指定表后缀时，将生成指定表，其余表不生成、并跳过忽略表配置
                //根据名称指定表生成
                .designatedTableName(new ArrayList<>())
                //根据表前缀生成
                .designatedTablePrefix(new ArrayList<>())
                //根据表后缀生成
                .designatedTableSuffix(new ArrayList<>())
                //忽略表名
                .ignoreTableName(ignoreTableName)
                //忽略表前缀
                .ignoreTablePrefix(ignorePrefix)
                //忽略表后缀
                .ignoreTableSuffix(ignoreSuffix).build();
        //配置
        Configuration config = Configuration.builder()
                //版本
                .version("1.0.0")
                //描述
                .description("数据库设计文档生成")
                //数据源
                .dataSource(dataSource)
                //生成配置
                .engineConfig(engineConfig)
                //生成配置
                .produceConfig(processConfig)
                .build();
        //执行生成
        new DocumentationExecute(config).execute();
    }
}
